#include "stdTcp.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "StdThread.h"
#include "../GlobalMessage.h" //加 ../ 是指上层路径
#include "DoubleLinkList.h"
#include "DataCenter.h"
#include "StdThreadPool.h"
#include "FileSystem.h"


#define ip "172.29.0.125"
#define port 8080

DLlist ClientList;//定义一个全局变量: 在线用户列表
FileSys *fs;// 定义一个全局变量: 文件系统

// 获得在线用户列表，返回的是一个字符串(因为必须是连续的内存地址)
char* GetOnlinelist()
{
    // 申请对上空间保存字符串
    char* content = (char *)malloc(ContentSize);
    if (content == NULL)
    {
        printf("GetOnlinelist malloc error\n");
        exit(-1);// 直接结束
    }
    memset(content, 0, ContentSize);// 清零

    DLNode *travelPoint = ClientList.head->next;
    // 从链表的第一个开始遍历
    while(travelPoint != NULL)
    {
        CInfo *c = (CInfo *)travelPoint->data;
        strcat(content, c->ClientName);
        strcat(content, ",");
        travelPoint = travelPoint->next;// 遍历
        
    }
    // 数组下标是从 0 开始
    content[strlen(content) - 1] = '\0';// 取出多余的 , 号
    return content;
}


// 需求响应
void SolveRequest(MSG *m, int clientSock)
{
    switch(m->flag)
    {
        // 注册逻辑
        case SIGUP:
        {
            // 当前用户名未被注册，
            if (IsUserExist(m->FromName) == false)
            {
                // 添加新用户
                if (AddNewUser(m->FromName, m->Content) == true)
                {
                    // 将新用户插入在线用户链表中才执行下面操作哦
                    InsertDLlistTial(&ClientList, CreateCInfo(m->FromName, clientSock));
                    TravelDLlist(&ClientList, PrintCInfo);
                    memset(m->Content, ContentSize, 0);
                    strcpy(m->Content, "注册成功"); 
                    CreateNewDirInFs(fs, m->FromName);
                }
                else
                {
                    memset(m->Content, ContentSize, 0);
                    strcpy(m->Content, "服务器错误"); 
                }
            }
            // 用户名已被注册
            else
            {
                memset(m->Content, ContentSize, 0);
                strcpy(m->Content, "用户名已被注册");
            }
            // 向客户端发送删除结果
            TcpServerSend(clientSock, m, sizeof(MSG));
            break;
        }
        // 登录逻辑
        case LOGIN:
        {
            // 用户是否存在
            if (IsUserExist(m->FromName) == true)
            {
                // 开始匹配
                if (IsAccountEqual(m->FromName, m->Content) == true)
                {
                    // 插入成功才能进行私聊哦
                    InsertDLlistTial(&ClientList, CreateCInfo(m->FromName, clientSock));
                    TravelDLlist(&ClientList, PrintCInfo);
                    memset(m->Content, ContentSize, 0);
                    strcpy(m->Content, "登录成功"); 
                }
                else
                {
                    memset(m->Content, ContentSize, 0);
                    strcpy(m->Content, "账号密码不匹配"); 
                }
            }
            else
            {
                memset(m->Content, ContentSize, 0);
                strcpy(m->Content, "账号不存在");
            }
            TcpServerSend(clientSock, m, sizeof(MSG));    
            break;
        }
        case CHAT:// 私聊
        case SENDFILE:// 文件发送(服务器端的逻辑是一样的)
        {
            DLlist findList = FindByElement(&ClientList, m->ToName, IsClientNameEqual);
            if (findList.len == 0)
            {
                printf("没有找到名称为[%s]的用户\n", m->ToName);
            }
            else
            {
                CInfo * c = (CInfo *)findList.head->next->data;
                printf("准备给[%s][套接字：%d]的用户发消息\n", c->ClientName, c->sock);
                TcpServerSend(c->sock, m, sizeof(MSG));
            }
            ClearDLlist(&findList, NULL);// 避免内存泄漏
            break;
        }
        case BROADCAST:// 广播逻辑
        {
            DLNode *travelPoint = ClientList.head->next;
            // 从链表的第一个开始遍历
            while(travelPoint != NULL)
            {
                CInfo *c = (CInfo *)travelPoint->data;
                // 比较字符串的目的：不是自己就转发
                if (strcmp(c->ClientName, m->FromName) != 0)
                {
                    TcpServerSend(c->sock, m, sizeof(MSG));
                }
                travelPoint = travelPoint->next;// 一个个往后遍历
            }
            break;
        }
        case ONLINELIST:// 在线用户列表
        {
            char * content = GetOnlinelist();
            printf("在线列表为： %s \n", content);
            strcpy(m->Content, content);// 参数回传
            TcpServerSend(clientSock, m, sizeof(MSG));
            free(content);
            break;
        }
        case UPLOAD:// 文件上传
        {
            int size = 0;
            memcpy(&size, m->Content, sizeof(int));
            if (size == -1)
            {
                memset(m->Content, 0, sizeof(m->Content));// 清空
                strcpy(m->Content, "UPDATEOK");
                TcpServerSend(clientSock, m, sizeof(MSG));
                break;
            }
            char fileName[NameSize] = { 0 };
            strcpy(fileName, m->Content + sizeof(int));
            WriteFileToFs(fs, m->FromName, fileName, m->Content + 24, size);
            break;
        }
        case FILELIST:
        {
            char * list = GetFileList(fs, m->FromName);
            if (list == NULL)
            {
                memset(m->Content, 0, sizeof(m->Content));
                strcpy(m->Content, "getFILELISTERROR");
            }
            else
            {
                memset(m->Content, 0, sizeof(m->Content));
                strcpy(m->Content, list);// 参数回传
                free(list);            
            }
            TcpServerSend(clientSock, m, sizeof(MSG));
            
            break;
        }
        default:
            break;
    }
}

// 每个客户端线程处理函数
void *ClientThreadHandle(void *arg)
{
    int clientSock = *((int *)arg);
    while (1)
    {
        MSG m;
        char msg[100] = { 0 };
        if (TcpServerRecv(clientSock, &m, sizeof(MSG)) == false)// 
        {
            //perror("recv error");
            printf("客户端[%d]已下线...\n", clientSock);
            break;
        }
        //printf("收到来自客户端[%d]的消息：%s\n", clientSock, msg);
        SolveRequest(&m, clientSock);
    }

    // 删除用户的逻辑
    RemoveByElement(&ClientList, (void *)clientSock, IsClientSockEqual, free);// free 用来释放结构体里的指针

    return NULL;
}

int main()
{
    if (DataCenterInit() == false)// 数据中心初始化
    {
        printf("数据中心初始化失败\n");
        return -1;
    }
    InitDLlist(&ClientList);// 在线列表初始化
    TcpS *s = TcpServerInit(ip, port);
    ThreadP *p = ThreadPoolInit(10, 2, 10, 3600);// 线程池初始化

    fs = FileSystemInit("./filesystem");// 文件系统初始化

    int clientSock = -1;
    // if (clientSock < 0)
    // {
    //     return -1;
    // }

    while ((clientSock = TcpServerAccept(s)) >= 0)// 允许多个客户端相连
    {
        printf("接入新的客户端，套接字是：%d\n", clientSock);
        Thread *t = ThreadInit(ClientThreadHandle, &clientSock);// 开启一个线程让他处理
        ThreadPoolAddTask(p, ClientThreadHandle, &clientSock);

    }


#if 0
    // 此时进程阻塞在这里，无法执行下面的发送消息
    // 怎么办？
    // 每一个新进来的客户端开辟一个线程,也就是实现大并发服务器

    while (1)
    {
        char msg[100] = { 0 };
        if (TcpServerRecv(clientSock, msg, 100) == false)// 0代表阻塞
        {
            //perror("recv error");
            printf("客户端已下线。。。\n");
            return -1;
        }
        printf("收到来自客户端的消息：%s\n", msg);
    }
#endif

    return 0;
}
